/*
*********************************************************************************************************
*
*                                           flash.c
*
* 文件名称 : flash.c
* 文件版本 : V0.01
* 文件描述 : 内部flash操作
* 编写人员 : HHL
* 修改人员 :
* 编修描述 : V0.01，时间2012.11.29
*********************************************************************************************************
*/
/*
*********************************************************************************************************
*                                           头文件描述
*********************************************************************************************************
*/
#include "flash.h"


/*
*********************************************************************************************************
*                                           预处理描述
*********************************************************************************************************
*/


/*
*********************************************************************************************************
*                                             静态函数
*********************************************************************************************************
*/
//获取写入的地址的sector区域
static uint16_t STM32F407FlashGetSector(uint32_t addr)
{
  if     (addr < STM32F407_FLASH_ADDT_SECTOR_1_HEAD)
    return(FLASH_Sector_0);
  else if(addr < STM32F407_FLASH_ADDT_SECTOR_2_HEAD)
    return(FLASH_Sector_1);
  else if(addr < STM32F407_FLASH_ADDT_SECTOR_3_HEAD)
    return(FLASH_Sector_2);
  else if(addr < STM32F407_FLASH_ADDT_SECTOR_4_HEAD)
    return(FLASH_Sector_3);
  else if(addr < STM32F407_FLASH_ADDT_SECTOR_5_HEAD)
    return(FLASH_Sector_4);
  else if(addr < STM32F407_FLASH_ADDT_SECTOR_6_HEAD)
    return(FLASH_Sector_5);
  else if(addr < STM32F407_FLASH_ADDT_SECTOR_7_HEAD)
    return(FLASH_Sector_6);
  else if(addr < STM32F407_FLASH_ADDT_SECTOR_8_HEAD)
    return(FLASH_Sector_7);
  else if(addr < STM32F407_FLASH_ADDT_SECTOR_9_HEAD)
    return(FLASH_Sector_8);
  else if(addr < STM32F407_FLASH_ADDT_SECTOR_10_HEAD)
    return(FLASH_Sector_9);
  else if(addr < STM32F407_FLASH_ADDT_SECTOR_11_HEAD)
    return(FLASH_Sector_10);
  else
    return(FLASH_Sector_11);
}
//从flash获取一个字的数据
static uint32_t getFlashWord(uint32_t addr)
{
  return(*((uint32_t *)addr));
}
//擦除一段sector
uint32_t eraseFlashSector(uint32_t flashAddr)
{
  FLASH_Status status = FLASH_COMPLETE;
  //检查flash地址是否对齐
  if((flashAddr < STM32F407_FLASH_ADDR_BASE) || (flashAddr % 4)) {
    return(0);
  }
  //关闭系统中断
  //CPU_IntDis();

  //解锁
  FLASH_Unlock();
  //禁止数据缓存
  FLASH_DataCacheCmd(DISABLE);
  //排除flash错误标记
  FLASH->SR |= 0xf1;
  FLASH_Unlock();

  //打开系统中断
  //CPU_IntEn();

  //擦除flash
  status = FLASH_EraseSector(STM32F407FlashGetSector(flashAddr), VoltageRange_3);

  FLASH_DataCacheCmd(ENABLE);

  if (status == FLASH_COMPLETE) {
    return(1);
  } else {
    return(0);
  }
}
/*
*********************************************************************************************************
*
*                                           wrireFlashWord
*                                          写入数据到flash
*
* 函数名称 : wrireFlashWord()
* 函数版本 : V0.01
* 功能描述 : 向flash写入word
*           : flashAddr,flash的存储地址，pdata,数据指针，len，写入长度
*           : 成功返回写入的数据长度，失败返回0
* 编写人员 : HHL
* 修改人员 :
* 编修描述 : V0.01，时间2013.11.30
*********************************************************************************************************
*/

uint32_t writeFlashWord(uint32_t flashAddr, uint32_t *pdata, uint32_t len)
{
  FLASH_Status status = FLASH_COMPLETE;
  uint32_t addrx      = 0;
  uint32_t endaddr    = 0;

  //检查flash地址是否对齐
  if((flashAddr < STM32F407_FLASH_ADDR_BASE) || (flashAddr % 4)) {
    return(0);
  }

  //CPU_IntDis();
  //解锁
  FLASH_Unlock();
  //禁止数据缓存
  FLASH_DataCacheCmd(DISABLE);
  //CPU_IntEn();


  addrx   =  flashAddr;				//写入的开始地址
  endaddr = (flashAddr + (4*len));  //写入的结束地址

  //主存储区需要擦除相应的sector
  if (addrx < STM32F407_FLASH_ADDT_SYSTEM_HEAD) {
    while (addrx < endaddr) {
      if ((getFlashWord(addrx)) != 0xffffffff) {
        FLASH->SR |= 0xf1;
        status = FLASH_EraseSector(STM32F407FlashGetSector(addrx), VoltageRange_3);
        if (status != FLASH_COMPLETE) {
          break;
        }
      }
      addrx += 4;
    }
  }

  if (status == FLASH_COMPLETE) {
    while (flashAddr < endaddr) {
      if (FLASH_ProgramWord(flashAddr, *pdata) != FLASH_COMPLETE)  {
        break;
      }
      flashAddr += 4;
      pdata     += 1;
    }
  }

  //CPU_IntDis();
  FLASH_DataCacheCmd(ENABLE);
  FLASH_Unlock();
  //CPU_IntEn();

  if(status == FLASH_COMPLETE) {
    return(len);
  } else {
    return(0);
  }
}


/*
*********************************************************************************************************
*
*                                           readFlashWord
*                                          读取数据从flash
*
* 函数名称 : readlashWord()
* 函数版本 : V0.01
* 功能描述 :
*           : flashAddr,flash的存储地址，pdata,数据指针，len，读取长度
*           : 成功返回数据长度，失败返回0
* 编写人员 : HHL
* 修改人员 :
* 编修描述 : V0.01，时间2013.11.30
*********************************************************************************************************
*/
uint32_t readFlashWord(uint32_t flashAddr, uint32_t *pdata, uint32_t len)
{
  if((flashAddr < STM32F407_FLASH_ADDR_BASE) || (flashAddr % 4))
    {
      return(0);
    }
  else
    {
      //关闭系统中断
      //CPU_IntDis();
      for(uint32_t i=0; i<len; i++)
        {
          *pdata = getFlashWord(flashAddr);
          pdata     += 1;
          flashAddr += 4;
        }
      //打开系统中断
      //CPU_IntEn();
      return(len);
      //
    }
}


/*
*********************************************************************************************************
*
*                                           changeSysSetFlash
*                                             更改系统数据
*
* 函数名称 : changeSysSetFlash()
* 函数版本 : V0.01
* 功能描述 :
*           : flashAddr,flash的存储地址，pdata,数据指针，len，读取长度
*           : 自动将Ver的值加1，在重新启动的时候可以判断是读还是写数据
* 编写人员 : HHL
* 修改人员 :
* 编修描述 : V0.01，时间2013.11.30
*********************************************************************************************************
*/

/*
*********************************************************************************************************
*
*                                             resetFactory
*                                            更改到工厂设置
*
* 函数名称 : resetFactory()
* 函数版本 : V0.01
* 功能描述 : 重设RTC，格式化flash存储区域
*           : 完成后将通过看门狗重启系统
* 编写人员 : HHL
* 修改人员 :
* 编修描述 : V0.01，时间2015.09.20
*********************************************************************************************************
*/
void resetFactory(uint32_t set)
{
  //	//强制重写RTC
  //	if(FACTORY_RESET_RTC == (set&FACTORY_RESET_RTC))
  //	{
  //		_RTC_Init(RTC_RESET);
  //	}
  //	//擦除flash数据
  //	if(FACTORY_RESET_FLASH == (set&FACTORY_RESET_FLASH))
  //	{
  //		eraseFlashSector((uint32_t)(SYS_SET_FLASH_HEAD_ADDR));
  //	}
  //	//重新启动
  //	iwdgSet(0, 8);
}
